package com.zdp.controller;

import com.zdp.common.domain.ResultInfo;
import com.zdp.common.util.*;
import com.zdp.config.RedisOperator;
import com.zdp.pojo.Users;
import com.zdp.pojo.bo.ShopcartBO;
import com.zdp.pojo.bo.UserBO;
import com.zdp.service.center.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

/**
 * @author sesshomaru
 * @date 2021/7/30
 */
@RestController
@RequestMapping("passport")
public class PassportController extends BaseController{

    @Autowired
    private UserService userService;

    @Autowired
    private RedisOperator redisOperator;

    /**
     * 校验用户名是否可用
     * @param username
     * @return
     */
    @GetMapping("/usernameIsExist")
    public ResultInfo usernameIsExist(@RequestParam String username) {
        // 1.判断入参不可以为空
        AssertUtil.isNotBlank(username, "用户名不能为空");
        // 2.查找用户注册名是否存在
        boolean isExist = userService.queryUserNameIsExist(username);
        AssertUtil.isTrue(isExist, "用户名已存在");
        // 3.请求成功，用户名不存在
        return ResultInfoUtil.buildSuccess("");
    }

    /**
     * 用户注册
     * @param userBO
     * @param request
     * @param response
     * @return
     */
    @PostMapping("/regist")
    public ResultInfo regist(@RequestBody UserBO userBO,
                                  HttpServletRequest request,
                                  HttpServletResponse response) {
        String username = userBO.getUsername();
        String password = userBO.getPassword();
        String confirmPwd = userBO.getConfirmPassword();

        // 0. 判断用户名和密码必须不为空
        if (StringUtils.isBlank(username) ||
                StringUtils.isBlank(password) ||
                StringUtils.isBlank(confirmPwd)) {
            return ResultInfoUtil.buildError("用户名或密码不能为空");
        }

        // 1. 查询用户名是否存在
        boolean isExist = userService.queryUserNameIsExist(username);
        if (isExist) {
            return ResultInfoUtil.buildError("用户名已经存在");
        }

        // 2. 密码长度不能少于6位
        if (password.length() < 6) {
            return ResultInfoUtil.buildError("密码长度不能少于6");
        }

        // 3. 判断两次密码是否一致
        if (!password.equals(confirmPwd)) {
            return ResultInfoUtil.buildError("两次密码输入不一致");
        }

        // 4. 实现注册
        Users userResult = userService.createUser(userBO);

        CookieUtils.setCookie(request, response, "user",
                JsonUtils.objectToJson(userResult), true);


        // TODO 生成用户token，存入redis会话
        // 同步购物车数据
        syncShopCatData(userResult.getId(), request, response);

        return ResultInfoUtil.buildSuccess(userResult);
    }

    @PostMapping("/login")
    public ResultInfo login(@RequestBody UserBO userBO,
                                 HttpServletRequest request,
                                 HttpServletResponse response) throws Exception {

        String username = userBO.getUsername();
        String password = userBO.getPassword();

        // 0. 判断用户名和密码必须不为空
        if (StringUtils.isBlank(username) ||
                StringUtils.isBlank(password)) {
            return ResultInfoUtil.buildError("用户名或密码不能为空");
        }

        // 1. 实现登录
        Users userResult = userService.queryUserForLogin(username,
                MD5Utils.getMD5Str(password));

        if (userResult == null) {
            return ResultInfoUtil.buildError("用户名或密码不正确");
        }

        userResult = setNullProperty(userResult);

        CookieUtils.setCookie(request, response, "user",
                JsonUtils.objectToJson(userResult), true);


        // TODO 生成用户token，存入redis会话
        // 同步购物车数据
        syncShopCatData(userResult.getId(), request, response);
        return ResultInfoUtil.buildSuccess(userResult);
    }


    /**
     * 退出登录
     * @param userId
     * @param request
     * @param response
     * @return
     */
    @PostMapping("/logout")
    public ResultInfo logout(@RequestParam String userId,
                             HttpServletRequest request,
                             HttpServletResponse response) {

        // 清除用户的相关信息的cookie
        CookieUtils.deleteCookie(request, response, "user");

        // TODO 用户退出登录，需要清空购物车
        // TODO 分布式会话中需要清除用户数据

        return ResultInfoUtil.buildSuccess("");
    }

    /**
     * 注册登录成功后同步cookie和redis中的购物车数据
     */
    private void syncShopCatData(String userId,
                                   HttpServletRequest request,
                                   HttpServletResponse response){
        /**
         * 京东采用这种cookie + redis的方式  而淘宝是必须登录的
         * 1.redis中无数据，如果cookie中购物车为空不做处理
         * 2.redis中无数据，如果cookie中的购物车不为空，需要同步到redis中
         * 3.redis中有数据，如果cookie中购物车为空那么直接把redis中的购物车覆盖本地cookie
         * 4.redis中有数据，如果cookie中购物车不为空。如果cookie中的某个商品在redis中存在，
         * 则以cookie为主，覆盖或者删除redis中，把cookie中的商品覆盖到redis中
         * 5. 同步到redis中后，覆盖本地cookie购物车的数据，保障购物车数据是同步最新的
         */

        // 从redis中获取购物车
        String shopcartJsonRedis = redisOperator.get(FOODIE_SHOPCART + ":" + userId);

        // 从cookie中获取购物车
        String shopcartStrCookie = CookieUtils.getCookieValue(request, FOODIE_SHOPCART, true);

        if (StringUtils.isBlank(shopcartJsonRedis)) {
            // redis为空，cookie不为空直接把cooke中的数据放入redis
            if (StringUtils.isNotBlank(shopcartStrCookie)) {
                redisOperator.set(FOODIE_SHOPCART + ":" + userId, shopcartStrCookie);
            }
        } else {
            // redis不为空，cookie不为空，合并cookie和redis中购物车的商品数据(同一规格商品则覆盖)
            if (StringUtils.isNotBlank(shopcartStrCookie)) {
                List<ShopcartBO> shopcartListRedis = JsonUtils.jsonToList(shopcartJsonRedis, ShopcartBO.class);
                List<ShopcartBO> shopcartListCookie = JsonUtils.jsonToList(shopcartStrCookie, ShopcartBO.class);
                // 定义一个待删除的list
                List<ShopcartBO> pendingDeleteList = new ArrayList<>();
                for (ShopcartBO redisShopcart : shopcartListRedis) {
                    String redisSpecId = redisShopcart.getSpecId();
                    for (ShopcartBO cookieShopcart : shopcartListCookie) {
                        String cookieSpecId = cookieShopcart.getSpecId();
                        // 1. 将redis中和cookie中同时存在的商品的购买数量采用cookie中的数量覆盖;
                        // 2. 同时将相同的商品保存到一个待删除的list中，将cookie中的商品移除后和更新商品购买数后的redis购物车数据集合合并
                        if (redisSpecId.equals(cookieSpecId)) {
                            redisShopcart.setBuyCounts(cookieShopcart.getBuyCounts());
                            // redis和cookie中都存在的商品存入待删除集合，从cookie集合中删除
                            pendingDeleteList.add(cookieShopcart);
                        }
                    }
                }
                // 移除cookie中与redis重复的商品数据
                shopcartListCookie.removeAll(pendingDeleteList);

                // 合并两个集合
                // 1. shopcartListCookie这时cookie中已经排除了和redis中重复的商品数据
                // 2. 并且将cookie中和redis相同的商品数据的购买个数进行了替换到了shopcartListRedis（cookie中的购买个数替换了redis中同种商品的购买个数)
                shopcartListRedis.addAll(shopcartListCookie);

                // 更新到redis和cookie中
                CookieUtils.setCookie(request, response, FOODIE_SHOPCART, JsonUtils.objectToJson(shopcartJsonRedis), true);
                redisOperator.set(FOODIE_SHOPCART + ":" + userId, JsonUtils.objectToJson(shopcartJsonRedis));

                // redis不为空，cookie为空,直接把redis覆盖到cookie中
            } else {
                CookieUtils.setCookie(request, response, FOODIE_SHOPCART, shopcartJsonRedis, true);
            }
        }

    }



    // 脱敏
    private Users setNullProperty(Users userResult) {
        userResult.setPassword(null);
        userResult.setMobile(null);
        userResult.setEmail(null);
        userResult.setCreatedTime(null);
        userResult.setUpdatedTime(null);
        userResult.setBirthday(null);
        return userResult;
    }

}
